package com.study.spring.oauth.githubDemo;

import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author zhangjunfei
 * @date 2021/12/7 11:20
 * 原文地址：https://mp.weixin.qq.com/s?__biz=MzAwMjk5Mjk3Mw==&mid=2247496514&idx=1&sn=1766baa2b93f7b7864243eb2927a71a0&chksm=9ac34d60adb4c47697f1bd1a71224559afc499753009a11e7e28015f02c8509201f512b0e5b7&mpshare=1&scene=24&srcid=0424ET9ixrbVy6vtZyazWxVH&sharer_sharetime=1619237720954&sharer_shareid=4e70123152a142f12badd70bdb2513fb#rd
 * 直接访问 登录地址localhost:8899/githubLogin
 */

@RestController
public class OAuthGitHubDemo {



    private static String GITHUB_CLIENT_ID = ""; //待填
    private static String GITHUB_CLIENT_SECRET = "";//待填
    private static String GITHUB_REDIRECT_URL = "http://127.0.0.1:8899/githubCallback";

    private Map<String, String> states = new HashMap<>();

    @RequestMapping("/githubLogin")
    public void githubLogin(HttpServletResponse response) throws IOException {
        //github认证服务器地址
        String githubOAuthUrl = "https://github.com/login/oauth/authorize";

        String state = UUID.randomUUID().toString();
        states.put("key", state);

        //传递参数 response_type、client_id、state、redirect_uri
        String param = "response_type=code&client_id=" + GITHUB_CLIENT_ID + "&state=" + state + "&redirect_uri=" + GITHUB_REDIRECT_URL;

        response.sendRedirect(githubOAuthUrl + "?" + param);

    }


    @RequestMapping("/githubCallback")
    public void githubCallback(String code, String state, HttpServletResponse response) throws IOException {

        if(!state.equals(states.get("key"))){
            System.out.println("验证失败：" + state);
        }

        // 2、向GitHub认证服务器申请令牌
        String url = "https://github.com/login/oauth/access_token";

        // 传递参数grant_type、code、redirect_uri、client_id
        String param = "grant_type=authorization_code&code=" + code + "&redirect_uri=" +
                GITHUB_REDIRECT_URL + "&client_id=" + GITHUB_CLIENT_ID + "&client_secret=" + GITHUB_CLIENT_SECRET;

        OkHttpClient okHttpClient = new OkHttpClient
                .Builder()
                .callTimeout(60, TimeUnit.SECONDS)
                .build();
        FormBody formBody = new FormBody.Builder()
                .add("grant_type", "authorization_code")
                .add("code", code)
                .add("redirect_uri", GITHUB_REDIRECT_URL)
                .add("client_id", GITHUB_CLIENT_ID)
                .add("client_secret", GITHUB_CLIENT_SECRET).build();
        Request request = new Request.Builder()
                .url(url)
                .post(formBody)
                .build();

        Response executeResponse = okHttpClient.newCall(request).execute();
        String string = executeResponse.body().string();

        /*
         * result示例：
         * 失败：error=incorrect_client_credentials&error_description=The+client_id+and%2For+client_secret+passed+are+incorrect.&
         * error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-oauth-app-access-token-request-errors%2F%23incorrect-client-credentials
         * 成功：access_token=7c76186067e20d6309654c2bcc1545e41bac9c61&scope=&token_type=bearer
         */
        System.out.println(string);
        String[] split = string.split("&");
        Map<String, String> params = new HashMap<>();
        for (String s : split) {
            String[] strings = s.split("=");
            if (strings.length == 2) {
                params.put(strings[0], strings[1]);
            }
        }
        String accessToken = params.get("access_token");
        String tokenType = params.get("token_type");

        // 3、向资源服务器请求用户信息，携带access_token和tokenType
        String userUrl = "https://api.github.com/user";
        String userParam = "token_type=" + tokenType;

        Request getMessageInfo = new Request.Builder()
                .url(userUrl + "?" + userParam)
                .header("Authorization","token "+accessToken)
                .get().build();


        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write(okHttpClient.newCall(getMessageInfo).execute().body().string());

    }
}
